package com.example.springbootlearn.netty.server;

import cn.hutool.core.collection.CollUtil;
import com.example.springbootlearn.netty.annotation.NettyHandler;
import com.example.springbootlearn.netty.config.NettyConfig;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.stream.ChunkedWriteHandler;
import io.netty.handler.timeout.IdleStateHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;

import java.util.Comparator;
import java.util.List;
import java.util.Map;

import static java.util.stream.Collectors.toList;

/**
 * @Author：OBM
 * @DATE：2023/2/24 17:38
 */
@Slf4j
@Service
public class NettyChannelInit extends ChannelInitializer<SocketChannel> {

    @Autowired
    private NettyConfig nettyConfig;
    @Autowired
    private ApplicationContext applicationContext;

    @Override
    protected void initChannel(SocketChannel ch) {
        ChannelPipeline pipeline = ch.pipeline();

        //打印日志的Handler，可以打印发送、接收的信息
        pipeline.addLast("print-logging", new LoggingHandler(LogLevel.DEBUG));
        //设置Http解码器
        pipeline.addLast("http-codes", new HttpServerCodec());
        pipeline.addLast("http-chunked", new ChunkedWriteHandler());
        //设置聚合器，封装http对像
        pipeline.addLast("aggregator", new HttpObjectAggregator(65536));
        // 进行设置心跳检测
        pipeline.addLast("idleStateHandler", new IdleStateHandler(nettyConfig.getReaderIdleTime(), nettyConfig.getWriterIdleTime(), nettyConfig.getAllIdleTime(), nettyConfig.getUnit()));

        pipeline.addLast(new WebSocketServerProtocolHandler(nettyConfig.getWebsocketPath()));

        List<ChannelHandler> channelHandlers = this.loadNettyHandler();
        if (CollUtil.isNotEmpty(channelHandlers)) {
            for (ChannelHandler channelHandler : channelHandlers) {
                pipeline.addLast(channelHandler);
            }
        }
    }

    private List<ChannelHandler> loadNettyHandler() {
        Map<String, Object> handlerMap = applicationContext.getBeansWithAnnotation(NettyHandler.class);
        return handlerMap.values()
                .stream()
                .map(x -> (ChannelHandler) x)
                .sorted(Comparator.comparing(x -> x.getClass().getAnnotation(NettyHandler.class).value()))
                .collect(toList());
    }


}
